/**
 * hmacMd5を取得するAPIです。
 * History:
 *          0.0.0.3 高速化・APIの変更
 *          0.0.0.2 高速化
 *          0.0.0.1 バージョン付け開始
 * Authors: Nazo
 * Version: 0.0.0.3
 * License: Public Domain
 */
module nazo.hmac_md5;

import nazo.mem, /*std.md5*/nazo.md5, std.base64, std.string, std.stdio;

static ulong[8] k_ipad=toMultiArr_ubyte!(typeof(k_ipad[0]),0x36);
static typeof(k_ipad[0])[8] k_opad=toMultiArr_ubyte!(typeof(k_ipad[0]),0x5c);
static int before_keylen=0;

///hmacMd5(キーを使ったハッシュ)の取得
///マルチスレッドで呼ばないでください＞＜
void hmacMd5(string data,string key,ubyte[16] rv){
  static ulong[8] k_ipad=toMultiArr_ubyte!(ulong,0x36);
  struct tmp{
    ulong[8] k_opad=toMultiArr_ubyte!(ulong,0x5c);
    ubyte[16] rv;
  }
  static tmp t;
  static int before_keylen=0;

  if(key.length>64){//未テスト
    sum(t.rv,cast(ubyte[])key);
    key=cast(string)t.rv;
  }

  uint i;
  for(;i<(key.length>>3);i++){
    k_ipad[i]=(cast(ulong*)key.ptr)[i]^toMultiArr_ubyte!(ulong,0x36);
    t.k_opad[i]=(cast(ulong*)key.ptr)[i]^toMultiArr_ubyte!(ulong,0x5c);
  }
  if(key.length&0b111){
    ulong s;
    (cast(ubyte*)&s)[0..key.length]=cast(ubyte[])key;
    k_ipad[i]=s^toMultiArr_ubyte!(ulong,0x36);
    t.k_opad[i]=s^toMultiArr_ubyte!(ulong,0x5c);
    i++;
  }
  for(;i<before_keylen;i++){
    k_ipad[i]=toMultiArr_ubyte!(ulong,0x36);
    t.k_opad[i]=toMultiArr_ubyte!(ulong,0x5c);
  }

/+  static MD5_CTX context;
  context.start();
  context.update(k_ipad);
  context.update(data);
  context.finish(t.rv);
  context.start();
  context.update((cast(ubyte*)&t)[0..80]);
  context.finish(rv);+/
  sum(t.rv, cast(ubyte*)k_ipad.ptr, cast(ubyte[])data);
  sum(rv, (cast(ubyte*)&t)[0..80]);
  before_keylen=key.length>>3+1;
}
